//
//  PixelWorldChatProtocol.swift
//  demo_swift
//
//  Created by kadenJack on 2022/7/15.
//

import Foundation
import HyphenateChat
import UIKit

typealias PixelWorldChatStatusBlock = ((_ result: PixelWorldChatStatusResult) -> Void)
let PixelWorldChatEMClient = EMClient.share
fileprivate let PixelWorldChatEaseUserPrefix = ""

//MARK: - 配置环信Key
extension PixelWorldChatWrapper: PixelWorldChatToolProtocol {
    
    //TODO: - 配置环信Key
    @discardableResult
    func configChat(_ appKey: String) -> Self {
        PixelWorldChatManager.share.configChat(appKey: appKey)
        return self
    }
    
}

//MARK: - 登录、注册、退出登录
extension PixelWorldChatWrapper {
    
    //TODO: - 登录(同步执行)
    /// 登录(同步执行)
    /// - Parameters:
    ///   - userName: 用户名
    ///   - password: 用户密码
    ///   - retryCount: 重试次数
    /// - Returns: 登录结果返回
    @discardableResult
    func login(userName: String, password: String = "", retryCount: Int = 0) -> PixelWorldChatStatusResult {
        guard !PixelWorldChatEMClient.isLoggedIn else {
            return .success(nil)
        }
        let aError = PixelWorldChatEMClient.login(withUsername: userName, password: password.isEmpty ? PixelWorldChatManager.share.defaultPassword : password)
        if let error = aError {
            if retryCount < PixelWorldChatManager.share.maxRetryCount {
                return self.login(userName: userName, password: password, retryCount: retryCount + 1)
            } else {
                return .failed(error.PixelWorldChatError)
            }
        }
        return .success(userName)
    }
    
    //TODO: - 注册（同步执行）
    /// 注册（同步执行）；可能会存在重复命名, 此处将自动随机生成名字
    /// - Parameters:
    ///   - userName: 用户名
    ///   - password: 密码
    ///   - retryCount: 重试次数
    /// - Returns: 注册结果
    func register(_ userName: String, password: String = "", retryCount: Int = 0) -> PixelWorldChatStatusResult {
        let aError = PixelWorldChatEMClient.register(withUsername: PixelWorldChatEaseUserPrefix + userName, password: password.isEmpty ? PixelWorldChatManager.share.defaultPassword : password)
        if let error = aError {
            if retryCount < PixelWorldChatManager.share.maxRetryCount {
                let newUserName = randomString()
                return self.register(PixelWorldChatEaseUserPrefix + newUserName, password: password, retryCount: retryCount + 1)
            } else {
                return .failed(error.PixelWorldChatError)
            }
        }
        return .success(userName)
    }
    
    //TODO: - 退出登录(同步执行)
    /// 登出登录(同步执行、通常是不会失败, 故此处将只返回成功状态）
    @discardableResult
    func logout() -> PixelWorldChatStatusResult {
        let aError = PixelWorldChatEMClient.logout(true)
        if let _ = aError {
            return self.logout()
        }
        return .success(nil)
    }
    
}

//MARK: - 发送消息
extension PixelWorldChatWrapper {
    
    //TODO: - 发送消息
    /// 发送消息
    func sendMessage(_ body: PixelWorldChatSendMessageBody, resultBlock: PixelWorldChatStatusBlock? = nil) {
        guard PixelWorldChatEMClient.isLoggedIn else {
            resultBlock?(.failed(.isLoggedIn))
            return
        }
        guard body.messageBody != .none else {
            resultBlock?(.failed(.message_bodyType))
            return
        }
        if body.isSendCmdMessage && body.messageBody == .image {
            resultBlock?(.failed(.message_cmd_image))
            return
        }
        guard let fromUser = PixelWorldChatEMClient.currentUsername, fromUser != body.conversationID else {
            resultBlock?(.failed(.message_toMe))
            return
        }
        // 构建消息体
        var messageBody: EMMessageBody?
        switch body.messageBody {
        case .image:
            guard let image = body.image, let imageData = image.pngData() else {
                resultBlock?(.failed(.message_image))
                return
            }
            messageBody = EMImageMessageBody(data: imageData, thumbnailData: imageData)
            break
        case .text, .emoji, .video:
            guard !body.message.isEmpty else {
                resultBlock?(.failed(.message_text))
                return
            }
            if body.isSendCmdMessage {
                messageBody = EMCmdMessageBody(action: body.message)
            } else {
                messageBody = EMTextMessageBody(text: body.message)
            }
            break
        default:
            break
        }
        guard !body.conversationID.isEmpty else {
            resultBlock?(.failed(.message_conversationID))
            return
        }
        guard let sendBody = messageBody else { return }
        // 构建扩展消息
        let info = ["messageBody": body.messageBody.rawValue, "video_channelName": body.channelName, "sender_identifies": body.sender_identifies, "receive_identifies": body.receive_identifies, "remarks": body.remarks, "sender_chatUser": fromUser] as [String : Any]
        // 构建发送消息体
        guard let chatMessageBody = EMChatMessage(conversationID: body.conversationID, from: fromUser, to: body.conversationID, body: sendBody, ext: info) else {
            return
        }
        let model = PixelWorldChat_analysisMessages([chatMessageBody]).first
        // 发送消息
        PixelWorldChatEMClient.chatManager?.send(chatMessageBody) { _ in
            
        } completion: { message, aError in
            if let error = aError {
                resultBlock?(.failed(error.PixelWorldChatError))
            } else {
                // 直接使用 'sayWake_analysisMessages' 可能会造成控制器不能释放问题;
                if let messageBody = message, var messageModel = model {
                    if let imageBody = messageBody.body as? EMImageMessageBody {
                        messageModel.imageUrl = imageBody.remotePath
                    }
                    messageModel.mesageID = messageBody.messageId
                    resultBlock?(.messages([messageModel]))
                    if !body.isSendCmdMessage {
                        /// 保存消息
                        ChatCache.saveMessages([messageModel])
                    }
                    if messageModel.messageBodyType == .video {
                        // 处理视频消息
                        let object = ["type": PixelWorldChatBlockPrefix.videoStatus, "result": PixelWorldChatStatusResult.messages([messageModel])] as [String : Any]
                        NotificationCenter.default.post(name: NSNotification.Name("SAYWAKE_SENDMESSAGENOTIFICATION"), object: object)
                    }
                }
                // 发送消息成功后刷新会话列表
                let object = ["type": PixelWorldChatBlockPrefix.conversation] as [String : Any]
                NotificationCenter.default.post(name: NSNotification.Name("SAYWAKE_SENDMESSAGENOTIFICATION"), object: object)
            }
        }
    }
    
    //TODO: - 获取历史消息
    /// 获取历史消息
    func historyMessages(_ conversationID: String) -> [PixelWorldChatMessageBodyModel] {
        return ChatCache.historyMessages(conversationID)
    }
    
    //TODO: - 解析接收到的消息
    /// 解析接收到的消息
    func PixelWorldChat_analysisMessages(_ messageBodys: [Any]) -> [PixelWorldChatMessageBodyModel] {
        var PixelWorldChatMessageModels = [PixelWorldChatMessageBodyModel]()
        if let messages = messageBodys as? [EMChatMessage] {
            messages.forEach { baseModel in
                PixelWorldChatMessageModels.append(self.PixelWorldChat_makeMessageModel(baseModel))
            }
        } else if let messages = messageBodys as? [EMConversation] {
            messages.forEach { conversation in
                if let model = conversation.latestMessage {
                    var messageModel = self.PixelWorldChat_makeMessageModel(model)
                    if messageModel.messageBodyType == .image {
                        messageModel.lastMessage = "[Picture]"
                    } else if messageModel.messageBodyType == .video {
                        messageModel.lastMessage = "[Video]"
                    } else if messageModel.messageBodyType == .emoji {
                        messageModel.lastMessage = "[Emoji]"
                    }
                    messageModel.unReadCount = Int(conversation.unreadMessagesCount)
                    PixelWorldChatMessageModels.append(messageModel)
                }
            }
        }
        if PixelWorldChatManager.share.ballChat_filterHuanXinChat {
            let models = PixelWorldChatMessageModels.filter({ ($0.lastMessage ?? "").contains("环信") == false })
            return models
        }
        return PixelWorldChatMessageModels
    }
    
    //TODO: - 构建基础消息模型
    /// 构建基础消息模型
    private func PixelWorldChat_makeMessageModel(_ messageModel: EMChatMessage) -> PixelWorldChatMessageBodyModel {
        let currentChatUser = PixelWorldChatEMClient.currentUsername
        
        var model = PixelWorldChatMessageBodyModel()
        model.sourceType = messageModel.direction == EMMessageDirectionReceive ? .receive : .sender
        model.sourceTypeStr = model.sourceType.rawValue
        if messageModel.chatType == EMChatTypeChat {
            model.messageType = .chat
        } else if messageModel.chatType == EMChatTypeGroupChat {
            model.messageType = .group
        }
        model.mesageID = messageModel.messageId
        model.lastTime = self.calculateLastMessageTime(serverTime: Int(messageModel.timestamp), isSecond: false)
        model.lastTimestamp = Int(messageModel.timestamp / 1000)
        model.easeUserID = messageModel.conversationId
        // 消息内容
        if let textBody = messageModel.body as? EMTextMessageBody {
            model.lastMessage = textBody.text
        } else if let imageBody = messageModel.body as? EMImageMessageBody {
            model.imageUrl = imageBody.remotePath
            model.lastMessage = "[Picture]"
        } else if let cmdTextBody = messageModel.body as? EMCmdMessageBody {
            model.lastMessage = cmdTextBody.action
        }
        // 备注信息
        if let otherInfo = messageModel.ext as? [String: Any] {
            /**
             // 构建扩展消息
             ["messageBody": body.messageBody, "video_channelName": body.channelName, "sender_identifies": body.sender_identifies, "receive_identifies": body.receive_identifies, "remarks": body.remarks, "sender_chatUser": fromUser]
             */
            if let messageBodyType = otherInfo["messageBody"] as? String {
                model.messageBodyType = PixelWorldChatMessageBodyType(rawValue: messageBodyType) ?? .text
                model.messageBodyTypeStr = model.messageBodyType.rawValue
            }
            // 如果发送消息的环信账户等于当前登录的环信账户, 则 userID 为接收者; 反之则是发布者
            let senderChatUser = otherInfo["sender_chatUser"] as? String
            if senderChatUser == currentChatUser {
                let receiveUserID = otherInfo["receive_identifies"] as? String
                model.userID = receiveUserID ?? ""
            } else {
                let senderUserID = otherInfo["sender_identifies"] as? String
                model.userID = senderUserID ?? ""
            }
            if let videoChannelName = otherInfo["video_channelName"] as? String {
                model.videoChannelName = videoChannelName
            }
            if let remarks = otherInfo["remarks"] as? String {
                model.remarks = remarks
            }
        }
        return model
    }
}

//MARK: - 会话相关
extension PixelWorldChatWrapper {
    
    //TODO: - 获取所有会话列表
    /// 获取所有会话列表
    func allConversations() -> PixelWorldChatStatusResult {
        let messages = ChatCache.conversationList()
        return .messages(messages)
    }
    
    //TODO: - 获取所有未读消息
    /// 获取所有未读消息
    func allUnreadCount() -> Int {
        var allCount = 0
        let models = ChatCache.conversationList()
        models.forEach({ conversation in
            let laestMessage = conversation.lastMessage ?? ""
            if !laestMessage.contains("环信") {
                allCount += Int(conversation.unReadCount)
            } else {
                if PixelWorldChatManager.share.ballChat_filterHuanXinChat {
                    self.cleanUnreadMessage(conversation.easeUserID)
                } else {
                    allCount += Int(conversation.unReadCount)
                }
            }
        })
        return allCount
    }
    
    //TODO: - 清空会话所有未读消息
    /// 清空会话所有未读消息
    func cleanUnreadMessage(_ conversation: EMConversation?) {
        ChatCache.cleanUnReadMessages(conversation?.conversationId)
        responseAction(.conversation)
    }
    
    func cleanUnreadMessage(_ conversationID: String?) {
        guard let messageID = conversationID else { return }
        ChatCache.cleanUnReadMessages(messageID)
        responseAction(.conversation)
    }
    
    //TODO: - 删除会话消息
    /// 删除会话消息
    /// - Parameters:
    ///   - conversationID: 会话ID
    ///   - isDeleteServer: 是否删除服务器消息
    ///   - isCleanMessage: 是否清空消息
    ///   - resultBlock: <#resultBlock description#>
    func deleteConversation(_ conversationID: String) {
        ChatCache.removeConversation(conversationID)
        self.responseAction(.conversation)
    }
    

    
}

//MARK: - EMErrorCode --->  PixelWorldChatStatusResultError
extension EMError {
    
    var PixelWorldChatError: PixelWorldChatStatusResultError {
        return .chat(code: Int(self.code.rawValue), msg: self.errorDescription)
    }
}

//MARK: - Array
extension Array where Element: Hashable {
    //TODO: - 移除重复数据
    /// 移除重复数据
    var removeRepeat: [Element] {
        return Array(Set(self))
    }
}


//MARK: - Protocol
protocol PixelWorldChatToolProtocol { }
extension PixelWorldChatToolProtocol {
    
    func getAssociatedObject<T>(_ object: Any, _ key: UnsafeRawPointer) -> T? {
        return objc_getAssociatedObject(object, key) as? T
    }
    
    func setRetainedAssociatedObject<T>(_ object: Any, _ key: UnsafeRawPointer, _ value: T) {
        objc_setAssociatedObject(object, key, value, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
    }
    
    // 随机生成字符串
    func randomString(_ maxCount: Int = 10) -> String {
        func random(min: Int, max: Int) -> Int {
            let index = arc4random()%UInt32(max)
            guard index < min || index > max else {
                return Int(index)
            }
            return random(min: min, max: max)
        }
        let allStrings = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890"
        var randomStr = ""
        for _ in 0..<maxCount {
            let index = random(min: 0, max: allStrings.count)
            let rang_1 = allStrings.index(allStrings.startIndex, offsetBy: index)
            randomStr += "\(allStrings[rang_1])"
        }
        return randomStr
    }
    
    /// 当前系统时间戳
    private func PixelWorldChat_timeStamp() -> TimeInterval {
        Date().timeIntervalSince1970
    }
    
    // 计算最后一条消息时间戳
    func calculateLastMessageTime(serverTime: Int, isSecond: Bool = true) -> String {
        let currentTime = Int(PixelWorldChat_timeStamp())
        let messageTime = isSecond ? serverTime : (serverTime / 1000)
        
        let time = currentTime - messageTime
        
        let days = (time/(3600*24))
        let hours = ((time-days*24*3600)/3600)
        let minute = (time-days*24*3600-hours*3600)/60
        //        let second = time-days*24*3600-hours*3600-minute*60
        
        if days > 0 {
            return self.timeIntervalChangeToTimeStr(timeInterval: Double(messageTime), "yyyy-MM-dd HH:mm")
        }
        if hours > 0 {
            return self.timeIntervalChangeToTimeStr(timeInterval: Double(messageTime), "HH:mm")
        }
        if minute > 0 {
            return minute > 10 ? self.timeIntervalChangeToTimeStr(timeInterval: Double(messageTime), "HH:mm") : "\(minute) minutes ago"
        }
        return "1 minutes ago"
    }
    
    // 时间戳转成字符串
    private func timeIntervalChangeToTimeStr(timeInterval: Double, _ dateFormat: String? = "yyyy-MM-dd HH:mm:ss") -> String {
        let date:Date = Date.init(timeIntervalSince1970: timeInterval)
        let formatter = DateFormatter.init()
        if dateFormat == nil {
            formatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
        }else{
            formatter.dateFormat = dateFormat
        }
        return formatter.string(from: date as Date)
    }
}



